from ctypes import c_short, sizeof
import _queue, io, queue, struct
import config, nvwave, tones
from .soundTouch import SoundTouch, SETTING_SEQUENCE_MILLISECONDS, SETTING_USE_ANTI_ALIAS_FILTER, SETTING_ANTI_ALIAS_FILTER_LENGTH, SETTING_USE_QUICK_SEEK, SETTING_SEEK_WINDOW_MILLISECONDS, SETTING_OVERLAP_MILLISECONDS
from threading import Event, RLock, Thread
BUFFERSIZE = 16000
class PcmPlayer(nvwave.WavePlayer):
    # 优化的PCM播放器类
    def run(self):
        while hasattr(self, 'queue'):
            try:
                buffer = self.queue.get(True, 0.01)
            except _queue.Empty:
                self.event.set()
                continue
            self.feed(buffer)
    def __init__(self, *args, **kwargs):
        # 初始化播放器
        super().__init__(*args, **kwargs)
        self.soundTouch = SoundTouch()
        self.soundTouch.setSampleRate(self.samplesPerSec)
        self.soundTouch.setChannels(self.channels)
        self.soundTouch.setSetting(SETTING_SEQUENCE_MILLISECONDS, 10)
        self.soundTouch.setSetting(SETTING_SEEK_WINDOW_MILLISECONDS, 10)
        self.soundTouch.setSetting(SETTING_USE_ANTI_ALIAS_FILTER, 1)
        self.soundTouch.setSetting(SETTING_ANTI_ALIAS_FILTER_LENGTH, 64)
        self.soundTouch.setSetting(SETTING_USE_QUICK_SEEK, 0)
        self.soundTouch.setSetting(SETTING_OVERLAP_MILLISECONDS, 10)
        self.lock = RLock()
        self.event = Event()
        self.queue = queue.Queue()
        self.frames = io.BytesIO()
        self.setStopped(True)
        self.thread = Thread(target = self.run)
        self.thread.start()
    def close(self):
        # 关闭播放器
        super().close()
        if hasattr(self, 'soundTouch'):
            del self.soundTouch
        if hasattr(self, 'queue'):
            del self.queue
        if hasattr(self, 'thread'):
            self.thread.join()
            del self.thread
    def __del__(self):
        self.close()
    def isStopped(self):
        with self.lock:
            return self.stopped
    def setStopped(self, stopped):
        with self.lock:
            self.stopped = stopped
    def skipSilence(self, data):
        # 跳过音频的静音区
        n = len(data)
        threshold = 30
        step = 20
        for i in range(0, n, step):
            j = sum(data[i: i + step]) / step
            if j < -threshold or j > threshold:
                return data[i:]
    def setTempo(self, value):
        # 设置倍速值
        self.soundTouch.setTempo(value)
    def play(self):
        # 准备播放
        self.setStopped(False)
        self.firstFrame = True
    def write(self, data):
        # 写入数据
        self.frames.write(data)
        num = self.frames.tell()
        if num < BUFFERSIZE:return
        self.flush()
    def flush(self):
        num = self.frames.tell()
        if num < 1:return
        data2 = self.frames.getvalue()
        self.frames.truncate(0)
        self.frames.seek(0)
        audio = struct.unpack('%dh' % (num / sizeof(c_short)), data2)
        if not audio:return
        self.soundTouch.putSamplesI16(audio)
        while not self.soundTouch.isEmpty():
            data2 = self.soundTouch.receiveSamplesI16()
            if not data2:break
            if self.firstFrame:
                data2 = self.skipSilence(data2)
                self.firstFrame = False
                if not data2:continue
            data3 = struct.pack('%dh' % len(data2), *data2)
            self.queue.put(data3)
            if self.isStopped(): break
        if hasattr(self, 'soundTouch'):
            self.soundTouch.flush()
            self.soundTouch.clear()
        self.event.clear()
        self.event.wait()
    def reset(self):
        # 重置播放器状态
        self.pause(False)
        if hasattr(self, 'queue'):
            self.queue.queue.clear()
    def stop(self):
        self.setStopped(True)
        self.reset()
        self.event.set()
        super().stop()